package handler

import (
	"GateWay/api/internal/config"
	"GateWay/api/internal/svc"
	"GateWay/api/tool"
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"io"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"
)

var SC *svc.ServiceContext

// Gateway HTTP网关结构体
type Gateway struct {
	ListenAddr string                 // 网关监听地址
	Upstreams  []config.RouteConfig   // 上游服务配置 path前缀 -> 目标URL
	Env        string                 // 网关的模式
	Log        *zap.Logger            // 日志
	router     *gin.Engine            // web引擎
	proxy      *httputil.ReverseProxy // 反向代理
	client     *http.Client           // 配置客户端
}

// NewGateway 创建网关实例
func NewGateway(SC *svc.ServiceContext) *Gateway {
	return &Gateway{
		ListenAddr: SC.Config.System.ListenAddr,
		Upstreams:  SC.Config.System.Upstreams,
		Log:        SC.Log,
		Env:        SC.Config.System.Env,
		client: &http.Client{
			Timeout: 30 * time.Second, // 设置超时
			Transport: &http.Transport{ // 连接池配置
				MaxIdleConns:        100,
				IdleConnTimeout:     90 * time.Second,
				DisableCompression:  true, // 缓冲设置：禁用压缩以降低 CPU 消耗
				DisableKeepAlives:   false,
				MaxIdleConnsPerHost: 20,
			},
		},
	}
}

// Init 初始化网关
func (g *Gateway) Init() error {
	// 设置Gin模式
	gin.SetMode(g.Env)
	g.router = gin.New()
	// 全局中间件
	g.router.Use(gin.Recovery())
	//, g.loggerMiddleware()

	// 注册路由
	g.registerRoutes()

	return nil
}

// registerRoutes 注册路由
func (g *Gateway) registerRoutes() {
	// 健康检查路由
	g.router.GET("/ping", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"status": "ok"})
	})

	// 动态路由，根据配置转发
	for _, router := range g.Upstreams {
		// 获取的路由的AuthRequired 判断是否需要认证
		if router.AuthRequired {
			g.router.Any(router.Path+"/*path", g.JWTAuth(), g.reverseProxyHandler(router.Service))
			continue
		}
		g.router.Any(router.Path+"/*path", g.reverseProxyHandler(router.Service))
	}

	// 默认路由
	g.router.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound, gin.H{
			"code":    http.StatusNotFound,
			"message": "Not Found",
		})
	})
}

// reverseProxyHandler 反向代理处理器（其实也就是一个中间件）
func (g *Gateway) reverseProxyHandler(target string) gin.HandlerFunc {
	// target 表示目标服务器的url
	// 下面的操作是将string转化为url.URL对象
	targetURL, err := url.Parse(target)
	if err != nil {
		g.Log.Error("url 解析失败：", zap.String("url", target), zap.Error(err))
		return func(c *gin.Context) {
			c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
				"error": "网关配置错误",
			})
		}
	}

	// 创建反向代理
	proxy := httputil.NewSingleHostReverseProxy(targetURL)
	proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
		g.Log.Error("代理错误", zap.Error(err))
		w.WriteHeader(http.StatusBadGateway)
	}

	return func(c *gin.Context) {
		// 记录原始请求信息
		g.Log.Info("proxying request",
			zap.String("method", c.Request.Method),
			zap.String("path", c.Request.URL.Path),
			zap.String("target", target),
		)
		// 修改请求信息
		c.Request.URL.Scheme = targetURL.Scheme
		c.Request.URL.Host = targetURL.Host
		c.Request.Host = targetURL.Host

		// 注入网关传递的用户ID（从中间件获取）
		if _, exists := c.Get("claims"); exists {
			Id := tool.GetUUID(c)
			// 设置网络请求头，将uuid传递
			c.Request.Header.Set("x-user-uuid", Id)
		}

		// 复制请求体，防止被多次读取
		if c.Request.Body != nil {
			bodyBytes, _ := io.ReadAll(c.Request.Body)
			c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
		}

		// 执行反向代理,也就是代理转发
		proxy.ServeHTTP(c.Writer, c.Request)
	}
}

// Run 启动网关
func (g *Gateway) Run() error {
	fmt.Println("网关启动，监听:", g.ListenAddr)
	return g.router.Run(g.ListenAddr)
}
